function patch(oldVnode, vnode) {
    let i, elm, parent;
    const insertedVnodeQueue = [];
    // cbs 生命周期函数
    for (i = 0; i < cbs.pre.length; ++i)
        cbs.pre[i]();
    if (isElement(api, oldVnode)) { // nodeTpye === 1，元素节点
        // 根据传入的oldVnode 创建虚拟dom
        oldVnode = emptyNodeAt(oldVnode);
    }
    else if (isDocumentFragment(api, oldVnode)) {// 是否问文档片段
        oldVnode = emptyDocumentFragmentAt(oldVnode);
    }
    if (sameVnode(oldVnode, vnode)) {// 比较 key ,is 和 sel是否一直，一样就是 samevnode
        patchVnode(oldVnode, vnode, insertedVnodeQueue);// 此处应该会比较
    }
    else {
        elm = oldVnode.elm;
        parent = api.parentNode(elm); // 父节点
        createElm(vnode, insertedVnodeQueue);
        if (parent !== null) {
            api.insertBefore(parent, vnode.elm, api.nextSibling(elm));
            removeVnodes(parent, [oldVnode], 0, 0);
        }
    }
    for (i = 0; i < insertedVnodeQueue.length; ++i) {
        insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]);
    }
    for (i = 0; i < cbs.post.length; ++i)
        cbs.post[i]();
    return vnode;
}
function patchVnode(oldVnode, vnode, insertedVnodeQueue) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    const hook = (_a = vnode.data) === null || _a === void 0 ? void 0 : _a.hook;
    (_b = hook === null || hook === void 0 ? void 0 : hook.prepatch) === null || _b === void 0 ? void 0 : _b.call(hook, oldVnode, vnode);
    const elm = (vnode.elm = oldVnode.elm);
    const oldCh = oldVnode.children;
    const ch = vnode.children;
    if (oldVnode === vnode)
        return;
    if (vnode.data !== undefined ||
        (isDef(vnode.text) && vnode.text !== oldVnode.text)) {
        (_c = vnode.data) !== null && _c !== void 0 ? _c : (vnode.data = {});
        (_d = oldVnode.data) !== null && _d !== void 0 ? _d : (oldVnode.data = {});
        for (let i = 0; i < cbs.update.length; ++i)
            cbs.update[i](oldVnode, vnode);
        (_g = (_f = (_e = vnode.data) === null || _e === void 0 ? void 0 : _e.hook) === null || _f === void 0 ? void 0 : _f.update) === null || _g === void 0 ? void 0 : _g.call(_f, oldVnode, vnode);
    }
    if (isUndef(vnode.text)) {
        if (isDef(oldCh) && isDef(ch)) {
            if (oldCh !== ch)
                updateChildren(elm, oldCh, ch, insertedVnodeQueue);
        }
        else if (isDef(ch)) {
            if (isDef(oldVnode.text))
                api.setTextContent(elm, "");
            addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
        }
        else if (isDef(oldCh)) {
            removeVnodes(elm, oldCh, 0, oldCh.length - 1);
        }
        else if (isDef(oldVnode.text)) {
            api.setTextContent(elm, "");
        }
    }
    else if (oldVnode.text !== vnode.text) {
        if (isDef(oldCh)) {
            removeVnodes(elm, oldCh, 0, oldCh.length - 1);
        }
        api.setTextContent(elm, vnode.text);
    }
    (_h = hook === null || hook === void 0 ? void 0 : hook.postpatch) === null || _h === void 0 ? void 0 : _h.call(hook, oldVnode, vnode);
}
function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue) {
    // 新旧节点开始结束索引及开始结束节点
    let oldStartIdx = 0;
    let newStartIdx = 0;
    let oldEndIdx = oldCh.length - 1;
    let oldStartVnode = oldCh[0];
    let oldEndVnode = oldCh[oldEndIdx];
    let newEndIdx = newCh.length - 1;
    let newStartVnode = newCh[0];
    let newEndVnode = newCh[newEndIdx];
    // 循环之后的操作
    let oldKeyToIdx;
    let idxInOld;
    let elmToMove;
    let before;
    // 循环，开始节点 < 结束节点 （新旧节点，任一个）
    // 没循环一次 新旧节点索引+1
    while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
        if (oldStartVnode == null) {
            oldStartVnode = oldCh[++oldStartIdx]; // Vnode might have been moved left
        }
        else if (oldEndVnode == null) {
            oldEndVnode = oldCh[--oldEndIdx];
        }
        else if (newStartVnode == null) {
            newStartVnode = newCh[++newStartIdx];
        }
        else if (newEndVnode == null) {
            newEndVnode = newCh[--newEndIdx];
        }
        else if (sameVnode(oldStartVnode, newStartVnode)) {// 比较 旧开始节点 与 新开始节点
            // 如果相同，那么执行pathcVnode，更新新旧节点的内容，children或者text
            patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue);
            oldStartVnode = oldCh[++oldStartIdx];
            newStartVnode = newCh[++newStartIdx];
        }
        else if (sameVnode(oldEndVnode, newEndVnode)) {// 旧结束节点 与新结束节点 比较
            patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue);
            oldEndVnode = oldCh[--oldEndIdx];
            newEndVnode = newCh[--newEndIdx];
        }
        else if (sameVnode(oldStartVnode, newEndVnode)) {// 旧开始节点 与新结束节点，
            // 如果相同，那么旧节点向右移到 末尾
            // Vnode moved right
            patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue);
            api.insertBefore(parentElm, oldStartVnode.elm, api.nextSibling(oldEndVnode.elm));
            oldStartVnode = oldCh[++oldStartIdx];
            newEndVnode = newCh[--newEndIdx];
        }
        else if (sameVnode(oldEndVnode, newStartVnode)) {// 旧结束接地那 与新开始节点
            // 旧的结束节点 移动到最左
            // Vnode moved left
            patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue);
            api.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
            oldEndVnode = oldCh[--oldEndIdx];
            newStartVnode = newCh[++newStartIdx];
        }
        else {// 以上四种都不满足
            if (oldKeyToIdx === undefined) {
                // 旧节点，给旧节点 赋值key(其实还是索引)， key与索引对应的map
                oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
            }
            // 根据可以来查询，新节点在 就旧节点中是否有对应的 节点
            idxInOld = oldKeyToIdx[newStartVnode.key];
            if (isUndef(idxInOld)) {// 没有对应的旧节点，那么新增节点，
                // New element
                api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
            }
            else {// 有对应的节点，先判断是否 节点是否相同，
                //如果相同，那么复用dom元素，更新其中的内容，不同，那么新建dom并插入对应位置
                elmToMove = oldCh[idxInOld];
                if (elmToMove.sel !== newStartVnode.sel) {
                    api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
                }
                else {
                    patchVnode(elmToMove, newStartVnode, insertedVnodeQueue);
                    oldCh[idxInOld] = undefined;
                    api.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm);
                }
            }
            newStartVnode = newCh[++newStartIdx];
        }
    }
    // 旧节点已经比较完毕，新节点还有剩余, 创建新的节点，并添加到对应的位置（newStartIdx, newEndIdx）
    if (newStartIdx <= newEndIdx) {
        before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm;
        addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
    }
    // 新节点 循环完毕，旧节点还有剩余，直接删除对应的元素
    if (oldStartIdx <= oldEndIdx) {
        removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
    }
}